/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Windows Forms Controls Class Library
 * Version 2.00
 * 
 * Advanced Panel Class
 *      Provides a UI container element that may be docked or undocked and re-sized.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Text;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace Adaptive.Foundation.Windows.Forms
{
    /// <summary>
    /// Provides a UI container element that may be docked or undocked and re-sized.
    /// </summary>
    [ToolboxBitmap(typeof(EmbeddedResourceFinder), "Adaptive.Foundation.Windows.Forms.AdvancedPanel.bmp")]
    public partial class AdvancedPanel : AdaptiveControlBase
    {
        /*--------------------------------------------------------------------------------
         * Public Event Definitions
         *------------------------------------------------------------------------------*/
        #region Public Event Definitions
        /// <summary>
        /// Occurs when the user clicks the top-right "X" icon.
        /// </summary>
        public event EventHandler CloseRequest;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Constants Declarations
         *------------------------------------------------------------------------------*/
        #region Private Constants Declarations
        private const int TITLE_HEIGHT = 20;
        private const int BORDER_WIDTH = 3;
        private const int CLOSE_POSITION = 16;
        private const int CLOSE_POSITION_TOP = 5;
        private const int CLOSE_POSITION_BOTTOM = 17;
        private const int DOCK_LEFT = 5;
        private const int DOCK_RIGHT = 21;
        private const int DOCK_TOP = 4;
        private const int DOCK_BOTTOM = 17;

        private const int PADDING_TOP = 20;
        private const int PADDING_LEFT = 1;
        private const int PADDING_RIGHT = 1;
        private const int PADDING_BOTTOM = 1;

        private const int TEXT_START = 16;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// A value indicating whether the user is pressing a mouse button.
        /// </summary>
        private bool _mouseDown = false;
        /// <summary>
        /// The last X-corordinate of the mouse.
        /// </summary>
        private int _lastX = 0;
        /// <summary>
        /// The last Y-coordinate of the mouse.
        /// </summary>
        private int _lastY = 0;
        /// <summary>
        /// A value indicating whether the user is draggin the right side of the control.
        /// </summary>
        private bool _right = false;
        /// <summary>
        /// A value indicating whether the user is draggin the bottom side of the control.
        /// </summary>
        private bool _bottom = false;
        /// <summary>
        /// A value indicating whether the user is draggin the left side of the control.
        /// </summary>
        private bool _left = false;
        /// <summary>
        /// A value indicating whether the user is draggin the top side of the control.
        /// </summary>
        private bool _top = false;
        /// <summary>
        /// The X-coordinate used to determine where the user clicked on the control.
        /// </summary>
        private int _clickX = 0;
        /// <summary>
        /// The Y-coordinate used to determine where the user clicked on the control.
        /// </summary>
        private int _clickY = 0;
        /// <summary>
        /// The font to use when drawing the title caption.
        /// </summary>
        private Font _titleFont;
        /// <summary>
        /// The control order sequence of the control.
        /// </summary>
        private int _sequence = 0;
        /// <summary>
        /// The background color for the title bar.
        /// </summary>
        private Color _titleBackColor = SystemColors.ActiveCaption;
        /// <summary>
        /// The foreground color for the title bar.
        /// </summary>
        private Color _titleForeColor = SystemColors.ActiveCaptionText;
        /// <summary>
        /// The cursor to display when the user is over the "X" icon.
        /// </summary>
        private Cursor _cursor = Cursors.UpArrow;
        /// <summary>
        /// The title to be displayed.
        /// </summary>
        private string _title = string.Empty;
        /// <summary>
        /// The brush used to fill the background.
        /// </summary>
        private SolidBrush _backColorBrush = null;
        /// <summary>
        /// The brush used to fill the title caption background.
        /// </summary>
        private SolidBrush _titleBackColorBrush = null;
        /// <summary>
        /// The brush used to fill the title text.
        /// </summary>
        private SolidBrush _titleForeColorBrush = null;
        /// <summary>
        /// The pen used to draw in the control foreground color.
        /// </summary>
        private Pen _foreColorPen = null;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public AdvancedPanel()
            : base()
        {
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();

            //Set the control style for user drawing.
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, false);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.FixedHeight, false);
            SetStyle(ControlStyles.FixedWidth, false);
            SetStyle(ControlStyles.Selectable, true);

            //Set the default title font.
            _titleFont = Font;

            //Set the paint objects.
            _backColorBrush = new SolidBrush(BackColor);
            _titleBackColorBrush = new SolidBrush(_titleBackColor);
            _titleForeColorBrush = new SolidBrush(_titleForeColor);
            _foreColorPen = new Pen(base.ForeColor);

            //Set the dock padding so no contained control can hide the title.
            base.DockPadding.Top = TITLE_HEIGHT;

        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
                if (_titleForeColorBrush != null)
                    _titleForeColorBrush.Dispose();
                if (_titleBackColorBrush != null)
                    _titleBackColorBrush.Dispose();
                if (_backColorBrush != null)
                    _backColorBrush.Dispose();
                if (_foreColorPen != null)
                    _foreColorPen.Dispose();
            }
            _titleFont = null;
            _cursor = null;
            _title = null;
            _backColorBrush = null;
            _titleBackColorBrush = null;
            _titleForeColorBrush = null;
            _foreColorPen = null;
            components = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets the background color for the control.
        /// </summary>
        /// <remarks>
        /// This overrides the base implementation to control the graphics objects used
        /// to draw the control.
        /// </remarks>
        /// <value>
        /// A <see cref="Color"/> structure.
        /// </value>
        [Browsable(true), Description("Gets or sets the background color for the control.")]
        public override Color BackColor
        {
            get { return base.BackColor; }
            set
            {
                //Dispose of brush.
                if (_backColorBrush != null)
                    _backColorBrush.Dispose();

                //Set the color.
                base.BackColor = value;
                _backColorBrush = new SolidBrush(base.BackColor);

                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the foreground color for the control.
        /// </summary>
        /// <remarks>
        /// This overrides the base implementation to control the graphics objects used
        /// to draw the control.
        /// </remarks>
        /// <value>
        /// A <see cref="Color"/> structure.
        /// </value>
        [Browsable(true), Description("Gets or sets the background color for the control.")]
        public override Color ForeColor
        {
            get { return base.ForeColor; }
            set
            {
                //Dispose of brush.
                if (_foreColorPen != null)
                    _foreColorPen.Dispose();

                //Set the color.
                base.ForeColor = value;
                _foreColorPen = new Pen(base.ForeColor);

                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the cursor to display when the user hovers over the "X" icon.
        /// </summary>
        /// <value>
        /// A <see cref="Cursor"/> object.
        /// </value>
        [Browsable(true), Description("Gets or sets the cursor to display when the user hovers over the 'X' icon.")]
        public Cursor CloseCursor
        {
            get { return _cursor; }
            set { _cursor = value; }
        }
        /// <summary>
        /// Gets or sets the color of the caption text.
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> structure.
        /// </value>
        [Browsable(true), Description("Gets or sets the color of the caption text.")]
        public Color TitleForeColor
        {
            get { return _titleForeColor; }
            set
            {
                //Dispose of brush.
                if (_titleForeColorBrush != null)
                    _titleForeColorBrush.Dispose();

                //Set value and create new brush.
                _titleForeColor = value;
                _titleForeColorBrush = new SolidBrush(_titleForeColor);

                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the background color of the caption text.
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> structure.
        /// </value>
        [Browsable(true), Description("Gets or sets the background color of the caption text.")]
        public Color TitleBackColor
        {
            get { return _titleBackColor; }
            set
            {
                //Dispose of brush.
                if (_titleBackColorBrush != null)
                    _titleBackColorBrush.Dispose();

                //Set value and create brush.
                _titleBackColor = value;
                _titleBackColorBrush = new SolidBrush(_titleBackColor);

                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the font to use for the caption text.
        /// </summary>
        /// <value>
        /// A <see cref="Font"/> object.
        /// </value>
        [Browsable(true), Description("Gets or sets the font to use for the caption text.")]
        public Font TitleFont
        {
            get { return _titleFont; }
            set
            {
                _titleFont = value;
                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the caption text.
        /// </summary>
        /// <value>
        /// A string.
        /// </value>
        [Browsable(true), Description("Gets or sets the caption text.")]
        public string Title
        {
            get { return _title; }
            set
            {
                _title = value;
                Invalidate();
            }
        }
        /// <summary>
        /// Gets the dock padding settings for all edges of the control.
        /// </summary>
        /// <remarks>
        /// This property overrides the basic implementation to force specific
        /// dock padding for the control.
        /// </remarks>
        /// <value>
        /// A <see cref="System.Windows.Forms.ScrollableControl.DockPaddingEdges"/> object.
        /// </value>
        public new DockPaddingEdges DockPadding
        {
            get
            {
                //Set the object before returning.
                base.DockPadding.Top = PADDING_TOP;
                base.DockPadding.Left = PADDING_LEFT;
                base.DockPadding.Right = PADDING_RIGHT;
                base.DockPadding.Bottom = PADDING_BOTTOM;
                return base.DockPadding;
            }
            set
            {
                //Set this just in case.
                base.DockPadding.Top = PADDING_TOP;
            }
        }
        /// <summary>
        /// Gets or sets the control sequencing value.
        /// </summary>
        /// <value>
        /// An ordinal sequence number.
        /// </value>
        [Browsable(true), DefaultValue(0),
        Description("Gets or sets the control sequencing value.")]
        public int Sequence
        {
            get { return _sequence; }
            set
            {
                _sequence = value;
                Invalidate();
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Raises the <see cref="CloseRequest"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="System.EventArgs"/> event arguments object.
        /// </param>
        protected virtual void OnCloseRequest(EventArgs e)
        {
            if (CloseRequest != null)
                CloseRequest(this, e);
        }
        /// <summary>
        /// Raises the <see cref="System.Windows.Forms.Control.MouseDown"/> event, Sets the cursor, 
        /// and prepares for a re-sizing opertion.
        /// </summary>
        /// <param name="e">
        /// A <see cref="MouseEventArgs"/> event arguments object containing information
        /// about the cursor location and mouse button that was pressed.
        /// </param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            //Raise base event.
            base.OnMouseDown(e);

            //Set values if the cursor is over a border.
            if (e.X >= Width - BORDER_WIDTH)
                //Right side.
                _right = true;

            if (e.Y >= Height - BORDER_WIDTH)
                //Bottom side.
                _bottom = true;

            if (e.X <= BORDER_WIDTH)
                //Left side.
                _left = true;

            if (e.Y <= BORDER_WIDTH)
                //Top size.
                _top = true;

            //Save the location in case this is a click operation.
            _clickX = e.X;
            _clickY = e.Y;

            //Set the cursor based on where it is.
            if ((_right) && (_bottom))
                Cursor = Cursors.SizeNWSE;
            else if ((_top) && (_left))
                Cursor = Cursors.SizeNWSE;
            else if (_right)
                Cursor = Cursors.SizeWE;
            else if (_bottom)
                Cursor = Cursors.SizeNS;
            else if (_top)
                Cursor = Cursors.SizeNS;
            else if (_left)
                Cursor = Cursors.SizeWE;
            else
                Cursor = Cursors.SizeAll;

            //Set values for the Mouse Move operations.
            _lastX = e.X;
            _lastY = e.Y;
            _mouseDown = true;

        }
        /// <summary>
        /// Raises the <see cref="System.Windows.Forms.Control.MouseMove"/> event, and resizes the control if the 
        /// user is dragging an edge.
        /// </summary>
        /// <param name="e">
        /// A <see cref="MouseEventArgs"/> event arguments object containing information
        /// about the cursor location and mouse button that was pressed.
        /// </param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            int closeX = Width - CLOSE_POSITION;	//The location of the "X" icon.

            //Raise base event.
            base.OnMouseMove(e);

            //If this is not a mouse draggomg operation, set the cursor based on 
            //mouse position.
            if (!_mouseDown)
            {
                if ((e.X >= Width - BORDER_WIDTH) && (e.Y >= Height - BORDER_WIDTH))
                    //Top Right cursor.
                    Cursor = Cursors.SizeNWSE;

                else if ((e.X <= BORDER_WIDTH) && (e.Y <= BORDER_WIDTH))
                    //Top Left cursor.
                    Cursor = Cursors.SizeNWSE;

                else if ((e.X >= Width - BORDER_WIDTH) || (e.X <= BORDER_WIDTH))
                    //Left or right sides.
                    Cursor = Cursors.SizeWE;

                else if ((e.Y >= Height - BORDER_WIDTH) || (e.Y <= BORDER_WIDTH))
                    //Top or bottom sides.
                    Cursor = Cursors.SizeNS;

                else if ((e.X >= closeX) && (e.X <= closeX + CLOSE_POSITION) &&
                    (e.Y >= CLOSE_POSITION_TOP) && (e.Y <= CLOSE_POSITION_BOTTOM))
                    //Set the "close" icon cursor.
                    Cursor = _cursor;
                else
                    //Default cursor.
                    Cursor = Cursors.Default;
            }
            else
            {
                //Resize the control based on where the user is dragging a side.
                if ((_right) && (_bottom))
                {
                    //Bottom right corner.
                    Width += (e.X - _lastX);
                    Height += (e.Y - _lastY);
                }
                else if (_right)
                    //Right size.
                    Width += (e.X - _lastX);

                else if (_bottom)
                    //Bottom size.
                    Height += (e.Y - _lastY);

                else if (_top && _left)
                {
                    //Top left cornder.
                    Top += (e.Y - _lastY);
                    Height -= (e.Y - _lastY);
                    Left += (e.X - _lastX);
                    Width -= (e.X - _lastX);
                }
                else if (_top)
                {
                    //Top side.
                    Top += (e.Y - _lastY);
                    Height -= (e.Y - _lastY);
                }
                else if (_left)
                {
                    //Left side.
                    Left += (e.X - _lastX);
                    Width -= (e.X - _lastX);
                }
                else
                {
                    //Moving control as a whole.
                    Top += e.Y - _lastY;
                    Left += e.X - _lastX;
                }
            }

            //Save mouse position.
            _lastX = e.X;
            _lastY = e.Y;
        }
        /// <summary>
        /// Raises the <see cref="System.Windows.Forms.Control.MouseUp"/> event, releases the mouse tracking/dragging
        /// variables, and docks/undocks or closes the control based on where the user
        /// clicked.
        /// </summary>
        /// <param name="e">
        /// A <see cref="MouseEventArgs"/> event arguments object containing information
        /// about the cursor location and mouse button that was pressed.
        /// </param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            int closeX = Width - CLOSE_POSITION;	//Position of X icon.

            //Raise the base event.
            base.OnMouseUp(e);

            //Reset internal tracking variables.
            _right = false;
            _bottom = false;
            _mouseDown = false;
            _left = false;
            _top = false;

            //If the user clicked o nteh thumbnail icon, change its docking.
            if ((_clickX >= DOCK_LEFT) && (_clickX <= DOCK_RIGHT) &&
                (_clickY >= DOCK_TOP) && (_clickY <= DOCK_BOTTOM))
            {
                //Dock to top if not docked, undock if docked.
                if (Dock == DockStyle.None)
                    Dock = DockStyle.Top;
                else
                    Dock = DockStyle.None;
                //Refresh controo.
                Refresh();
            }
            else if ((_clickX >= closeX) && (_clickX <= closeX + CLOSE_POSITION) &&
                (_clickY >= CLOSE_POSITION_TOP) && (_clickY <= CLOSE_POSITION_BOTTOM))
            {
                //IF the user clicks on the X icon, try to "close" the control.
                OnCloseRequest(new EventArgs());
            }

            //Reset tracking variables.
            _clickX = 0;
            _clickY = 0;
            Cursor = Cursors.Default;
        }
        /// <summary>
        /// Paints the background of the control.
        /// </summary>
        /// <param name="e">
        /// A <see cref="PaintEventArgs"/> event arguments object containing the 
        /// <see cref="Graphics"/> object user to draw the control.
        /// </param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //Fill the background
            e.Graphics.FillRectangle(_backColorBrush, 0, 0, Width, Height);
        }
        /// <summary>
        /// Paints the control.
        /// </summary>
        /// <param name="e">
        /// A <see cref="PaintEventArgs"/> event arguments object containing the 
        /// <see cref="Graphics"/> object user to draw the control.
        /// </param>
        protected override void OnPaint(PaintEventArgs e)
        {
            int textTop = 0;			//The top Y location at which to draw the title text.
            int closeX = 0;				//The X position for the "X" icon.

            //Get the location for the text.
            textTop = (int)(9 - ((int)e.Graphics.MeasureString(_title, _titleFont).Height) / 2);

            //Draw the control rectangle.
            e.Graphics.DrawRectangle(_foreColorPen, 0, 0, Width - 1, Height - 1);

            //Draw the title rectangle.
            e.Graphics.FillRectangle(_titleBackColorBrush, 0, 0, Width, TITLE_HEIGHT);

            //Draw the title caption.
            e.Graphics.DrawString(_sequence.ToString() + ": " + _title, _titleFont, _titleForeColorBrush, TEXT_START, textTop);

            //If docked or not docked, draw the appropriate thumbnail image.
            if (Dock == DockStyle.None)
            {
                e.Graphics.DrawRectangle(_foreColorPen, 6, 5, 6, 4);
                e.Graphics.DrawLine(_foreColorPen, 6, 8, 11, 8);
                e.Graphics.DrawLine(_foreColorPen, 6, 4, 6, 10);
                e.Graphics.DrawLine(_foreColorPen, 3, 7, 6, 7);
            }
            else
            {
                e.Graphics.DrawRectangle(_foreColorPen, 6, 5, 4, 5);
                e.Graphics.DrawLine(_foreColorPen, 9, 5, 9, 10);
                e.Graphics.DrawLine(_foreColorPen, 4, 10, 11, 10);
                e.Graphics.DrawLine(_foreColorPen, 8, 10, 8, 14);
            }

            //Draw the "X" icon.
            closeX = Width - CLOSE_POSITION;
            e.Graphics.DrawLine(_foreColorPen, closeX, 6, closeX + 8, 14);
            e.Graphics.DrawLine(_foreColorPen, closeX + 1, 6, closeX + 9, 14);
            e.Graphics.DrawLine(_foreColorPen, closeX + 8, 6, closeX, 14);
            e.Graphics.DrawLine(_foreColorPen, closeX + 9, 6, closeX + 1, 14);
        }
        /// <summary>
        /// Creates and assigns the event handlers for the items contained within the control.
        /// </summary>
        protected override void AssignEventHandlers()
        {
        }
        /// <summary>
        /// Removes the event handlers for the items contained within the control.
        /// </summary>
        protected override void RemoveEventHandlers()
        {
        }
        /// <summary>
        /// Initializes the content of the control before the event handlers are assigned.
        /// </summary>
        protected override void InitializeContent()
        {
        }
        /// <summary>
        /// This method is invoked in the main UI thread to perform any neccessary
        /// updates to the UI.
        /// </summary>
        /// <remarks>
        /// Calling the related <see cref="AdaptiveControlBase.UpdateControl()"/> is used to prevent illegal 
        /// cross-threaded UI update calls.
        /// </remarks>
        protected override void UpdateCurrentControlContents()
        {
            Invalidate();
            Refresh();
        }
        /// <summary>
        /// This method is invoked in the main UI thread to perform any neccessary
        /// updates to the UI.
        /// </summary>
        /// <remarks>
        /// Calling the related <see cref="AdaptiveControlBase.UpdateControl(object[])"/> is used to prevent illegal 
        /// cross-threaded UI update calls.
        /// </remarks>
        /// <param name="data">
        /// The data supplied to the control to update the internal controls with.
        /// </param>
        protected override void UpdateCurrentControlContents(object[] data)
        {
            Invalidate();
            Refresh();
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Exposes the internal <see cref="System.Windows.Forms.Control.UpdateZOrder"/> method.
        /// </summary>
        public void UpdateZPosition()
        {
            UpdateZOrder();
        }
        #endregion
    }
}
